package cn.hf.mychat.controller;


import cn.hf.mychat.constanst.Const;
import cn.hf.mychat.constanst.Week;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日期处理工具类
 *
 * @author Roskin
 */
@Slf4j
public final class DateUtils {
    private DateUtils() {
    }

    /**
     * 给指定的日期加上(减去)月份
     *
     * @param date    指定日期
     * @param pattern 日期格式
     * @param num     月数，当num>1表示加上num月，当num<0 减去num月
     * @return
     */
    public static String addMoth(Date date, String pattern, int num) {
        return add(date, pattern, num, Calendar.MONTH);
    }

    /**
     * 给指定的日期加上(减去)月份
     *
     * @param date 指定日期
     * @param num  月数，当num>1表示加上num月，当num<0 减去num月
     * @return
     */
    public static Date addMoth(Date date, int num) {
        Calendar calender = Calendar.getInstance();
        calender.setTime(date);
        calender.add(Calendar.MONTH, num);
        return calender.getTime();
    }

    /**
     * 给制定的时间加上(减去)天
     *
     * @param date    指定日期
     * @param pattern 日期格式
     * @param num     天数，当num>1表示加上num天，当num<0 减去num天
     * @return
     */
    public static String addDay(Date date, String pattern, int num) {
        return add(date, pattern, num, Calendar.DATE);
    }

    /**
     * 增加天数
     *
     * @param date
     * @param dayAmount
     * @return
     */
    public static Date addDay(Date date, int dayAmount) {
        return addInteger(date, Calendar.DATE, dayAmount);
    }

    /**
     * 根据日期格式，返回当前时间
     *
     * @param pattern 日期格式
     * @return
     */
    public static String getNowTime(String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        return simpleDateFormat.format(new Date());
    }

    /**
     * 根据日期字符串返回对应Date类型
     *
     * @param dateStr 日期字符串
     * @param pattern 日期格式
     * @return
     * @throws ParseException 解析出现异常时抛出。
     */
    public static Date parse(String dateStr, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        try {
            return simpleDateFormat.parse(dateStr);
        } catch (ParseException e) {
            log.info("date parse error {},{}", pattern, dateStr, e);
        }
        return new Date();
    }

    /**
     * 使用预设格式提取字符串日期(yyyy-MM-dd HH:mm:ss)格式
     *
     * @param datestr 日期字符串
     * @return
     * @throws ParseException
     */
    public static Date parse(String datestr) {
        return parse(datestr, Const.DATE_FULL_STR);
    }

    /**
     * 与当天日期比较，返回相差的天数
     *
     * @param date 要比较的日期
     * @return 相差的天数
     */
    public static int compareDateWithNow(Date date) {
        Date now = new Date();
        int num = date.compareTo(now);
        return num;
    }

    /**
     * 与当前时间戳进行比较
     *
     * @param dateTime 要比较的时间戳
     * @return
     */
    public static int compareDateWithNow(long dateTime) {
        long now = dateToUnixTimestamp();
        if (dateTime > now) {
            return 1;
        } else if (dateTime < now) {
            return -1;
        } else {
            return 0;
        }
    }

    /**
     * 将指定的日期转换成Unix时间戳
     *
     * @param dateStr 需要转换的日期 yyyy-MM-dd HH:mm:ss
     * @return 日期所对应的时间戳
     * @throws ParseException
     */
    public static long dateToUnixTimestamp(String dateStr) throws ParseException {
        long timestamp = new SimpleDateFormat(Const.DATE_FULL_STR).parse(dateStr).getTime();
        return timestamp;
    }

    /**
     * 将当前日期转换成Unix时间戳
     *
     * @return 当前时间戳
     */
    public static long dateToUnixTimestamp() {
        long timestamp = new Date().getTime();
        return timestamp;
    }

    /**
     * 将指定的日期转换成Unix时间戳
     *
     * @param dateStr 需要转换的日期字符串
     * @param pattern 日期格式
     * @return 时间戳
     * @throws ParseException
     */
    public static long dateToUnixTimestamp(String dateStr, String pattern) throws ParseException {
        long timestamp = new SimpleDateFormat(pattern).parse(dateStr).getTime();
        return timestamp;
    }

    /**
     * 将Unix时间戳转换成日期,格式:yyyy-MM-dd HH:mm:ss
     *
     * @param timestamp 时间戳
     * @return
     */
    public static String unixTimestampToDate(long timestamp) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(Const.DATE_FULL_STR);
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        return simpleDateFormat.format(new Date(timestamp));
    }

    /**
     * 将Unix时间戳转换成日期
     *
     * @param timestamp 时间戳
     * @param pattern   日期格式
     * @return
     */
    public static String timeStampToDate(long timestamp, String pattern) {
        return new SimpleDateFormat(pattern).format(new Date(timestamp));
    }

    /**
     * 将Unix时间戳转换成日期
     *
     * @param timestamp 时间戳
     * @return
     */
    public static String timeStampToDate(long timestamp) {
        return new SimpleDateFormat(Const.DATE_FULL_STR).format(new Date(timestamp));
    }

    /**
     * 日期相加减
     *
     * @param date    指定日期
     * @param pattern 日期格式
     * @param num     添加的数字，当num>0时，表示相加，当num<0时，表示相减
     * @param type    日期类型
     * @return
     */
    private static String add(Date date, String pattern, int num, int type) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        Calendar calender = Calendar.getInstance();
        calender.setTime(date);
        calender.add(type, num);
        return simpleDateFormat.format(calender.getTime());
    }

    /**
     * 判断字符串是否为日期格式
     *
     * @param strDate 日期字符串
     * @return
     */
    public static boolean isDate(String strDate) {
        String regex = "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(strDate);
        if (matcher.matches()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据日期解析字符串
     *
     * @param date
     * @return
     */
    public static String toDateStr(Date date) {
        return toDateStr(date, Const.DATE_FULL_STR);
    }

    /**
     * 根据日期解析字符串
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String toDateStr(Date date, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        return simpleDateFormat.format(date);
    }

    /**
     * 根据时间获得日期
     *
     * @param hour
     * @return
     */
    public static Date getClock(int hour) {
        Calendar calendar = Calendar.getInstance();
        if (calendar.get(Calendar.HOUR_OF_DAY) > hour) {
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 校验日期是否合法
     *
     * @param s
     * @return
     */
    public static boolean isValidDate(String s) {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        try {
            fmt.parse(s);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取到今年年份
     *
     * @return
     */
    public static int getThisYear() {
        return getCalendar().get(Calendar.YEAR);
    }

    /**
     * 获取当前月份
     *
     * @return
     */
    public static int getThisMonth() {
        return getCalendar().get(Calendar.MONTH) + 1;
    }

    /**
     * 获取当天的日期
     *
     * @return
     */
    public static int getThisDay() {
        return getCalendar().get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取当天日期
     *
     * @return
     */
    public static Calendar getCalendar() {
        return Calendar.getInstance();
    }

    /**
     * 获得当前时间
     *
     * @return
     */
    public static Date getNow() {
        return getCalendar().getTime();
    }

    /**
     * 根据传入的时间戳转换为Date对象
     *
     * @param date
     * @return
     */
    public static Date getDate(long date) {
        return new Date(date);
    }

    /**
     * 将传入的时间戳转换为对应时间的字符串
     *
     * @param date
     * @return
     */
    public static String getDateStr(long date) {
        return new SimpleDateFormat(Const.DATE_SMALL_STR).format(getDate(date));
    }

    public static String getDateStr(String dateFormat, Date date) {
        return new SimpleDateFormat(dateFormat).format(date);
    }

    /**
     * 将传入的日期转换为对应时间的字符串
     *
     * @param date
     * @return
     */
    public static String getDateStr(Date date) {
        return new SimpleDateFormat(Const.DATE_SMALL_STR).format(date);
    }

    /**
     * 获取指定日期的开始时间：如2018-11-16 00:00:00
     *
     * @param date
     * @return
     */
    public static Date getBeginTime(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        return c.getTime();
    }

    /**
     * 获取指定日期的结束时间：如2018-11-16 23:59:59
     *
     * @param date
     * @return
     */
    public static Date getEndTime(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        return c.getTime();
    }

    /**
     * 获取日期就周几
     *
     * @param date
     * @return
     */
    public static Week getWeek(Date date) {
        Week week = null;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int weekNumber = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        switch (weekNumber) {
            case 0:
                week = Week.SUNDAY;
                break;
            case 1:
                week = Week.MONDAY;
                break;
            case 2:
                week = Week.TUESDAY;
                break;
            case 3:
                week = Week.WEDNESDAY;
                break;
            case 4:
                week = Week.THURSDAY;
                break;
            case 5:
                week = Week.FRIDAY;
                break;
            case 6:
                week = Week.SATURDAY;
                break;
        }
        return week;
    }

    /**
     * 获取两个日期相差的天数
     *
     * @param date      日期字符串
     * @param otherDate 另一个日期字符串
     * @return 相差天数
     * @throws ParseException
     */
    public static int getIntervalDays(String date, String otherDate) throws ParseException {
        return getIntervalDays(parse(date), parse(otherDate));
    }

    /**
     * 获取两个日期相差的天数
     *
     * @param date      日期
     * @param otherDate 另一个日期
     * @return 相差天数
     */
    public static int getIntervalDays(Date date, Date otherDate) {
        long time = Math.abs(date.getTime() - otherDate.getTime());
        return (int) (time / (24 * 60 * 60 * 1000));
    }

    /**
     * 获取两个日期相差的天数
     *
     * @param date      日期
     * @param otherDate 另一个日期
     * @return 相差天数 有正负标志
     */
    public static int getIntervalDay(Date date, Date otherDate) {
        long time = date.getTime() - otherDate.getTime();
        return (int) (time / (24 * 60 * 60 * 1000));
    }

    /**
     * 获取本月第一天
     *
     * @return
     */
    public static String firstDayOnMonth() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
        String first = format.format(c.getTime());
        return first;
    }

    /**
     * 获取当月最后一天
     *
     * @return
     */
    public static String lastDayOnMonth() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
        String last = format.format(ca.getTime());
        return last;
    }

    /**
     * 获取30天前的日期
     *
     * @return
     */
    public static String getBeforThirtyDay() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.DATE, -30);
        String beforThirtyDay = format.format(ca.getTime());
        return beforThirtyDay;
    }

    /**
     * 获取最近七天的日期
     *
     * @return
     */
    public static List<Date> getLastSevenDays() {
        List<Date> sevenDaysList = new ArrayList<>();
        for (int i = -6; i <= 0; i++) {
            sevenDaysList.add(addDay(new Date(), i));
        }
        return sevenDaysList;
    }

    /**
     * 增加日期中某类型的某数值。如增加日期
     *
     * @param date     日期
     * @param dateType 类型
     * @param amount   数值
     * @return 计算后日期
     */
    public static Date addInteger(Date date, int dateType, int amount) {
        Date temp = null;
        if (date != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(dateType, amount);
            temp = calendar.getTime();
        }
        return temp;
    }

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    /**
     * 获取年龄
     *
     * @param date 日期
     * @return 年龄
     */
    public static String getAge(Date date) {
        try {
            Calendar now = Calendar.getInstance();
            //当前时间
            now.setTime(new Date());
            Calendar birth = Calendar.getInstance();
            birth.setTime(date);

            int age;
            //如果传入的时间，在当前时间的后面，返回0岁
            if (birth.after(now)) {
                age = 0;
            } else {
                age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR);
                if (now.get(Calendar.DAY_OF_YEAR) > birth.get(Calendar.DAY_OF_YEAR)) {
                    age += 1;
                }
            }
            return Integer.toString(age);
        } catch (Exception e) {
            log.info("Get age error.", e);
            return "0";
        }
    }
}
